/**
 * 任务按顺序执行
 */
var taskSync = function () {
    this._index = -1;
    this._list = [];
    this._end = null;
}
/**
 * @param {(next:Function,retry:Function,end:Function)=>any} cb
 * @returns {taskSync}
 */
taskSync.prototype.add = function (cb) {
    this._list.push(cb);
    return this;
}
/**
 * @param {Function} finish
 */
taskSync.prototype.start = function (finish) {
    this._index = -1;
    this._end = finish;
    this.next();
}

taskSync.prototype.next = function () {
    if (++this._index < this._list.length) {
        this.retry();
    } else {
        this.end(this._list.length);
    }
}

taskSync.prototype.end = function () {
    this._index = this._list.length;
    this._end && this._end(this._list.length);
}

taskSync.prototype.retry = function () {
    this._list[this._index] && this._list[this._index](() => this.next(), () => this.retry(), () => this.end());
}

taskSync.prototype.size = function () {
    return this._list.length;
}

/**
 * 任务同时执行
 */
var taskASync = function () {
    this._index = -1;
    this._list = [];
    this._end = null;
}
/**
 * @param {(next:Function,retry:Function)=>any} cb
 * @returns {taskASync}
 */
taskASync.prototype.add = function (cb) {
    this._list.push(cb);
    return this;
}
/**
 * @param {Function} finish
 */
taskASync.prototype.start = function (finish) {
    this._index = -1;
    this._end = finish;
    if (this._list.length) {
        for (let index = 0; index < this._list.length; index++) {
            this.retry(index);
        }
    } else {
        this._end && this._end(this._list.length);
    }
}

taskASync.prototype.next = function () {
    this._index++;
    if (this._index === this._list.length - 1) {
        this._end && this._end(this._list.length);
    }
}

taskASync.prototype.retry = function (index) {
    const element = this._list[index];
    element && element(() => this.next(), () => this.retry(index));
}

taskASync.prototype.size = function () {
    return this._list.length;
}


/**
 * 任务按顺序执行
 * @return {taskSync}
 */
exports.createSync = function createSync() {
    return new taskSync();
};

/**
 * 任务同时执行
 * @return {taskASync}
 */
exports.createASync = function createASync() {
    return new taskASync();
};

/**
 * 执行单个任务
 * @param {(retry: function)=> void} fun 
 */
exports.excute = function excute(fun) {
    fun(function retry() {
        excute(fun);
    })
}